package com.changyinBus.web.controller.service.impl;

import com.changyinBus.common.core.redis.RedisCache;
import com.changyinBus.common.utils.StringUtils;
import com.changyinBus.common.utils.uuid.UUID;
import com.changyinBus.web.controller.bean.AccessTokenResult;
import com.changyinBus.web.controller.bean.WeChatUserInfo;
import com.changyinBus.web.controller.service.WeChatWebLoginService;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.URLEncoder;

@Service("WeChatWebLoginService")
public class WeChatWebLoginServiceImpl implements WeChatWebLoginService {
    private static final Logger log = LoggerFactory.getLogger(WeChatWebLoginServiceImpl.class);
    @Resource
    private RedisCache redisCache;
    @Value("${wechat.open.appId}")
    private String appId;
    @Value("${wechat.open.appSecret}")
    private String appSecret;
    @Value("${wechat.open.redirectUri}")
    private String redirectUri;

    private final OkHttpClient httpClient = new OkHttpClient();
    // 微信接口地址
    private static final String AUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize";
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
    private static final String USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo";

    @Override
    public String generateAuthUrl(String state) {
        // 将 state 存储到 Redis，设置10分钟过期
        String key = "wechat:state:" + state;
        redisCache.setCacheObject(key, state, 10, java.util.concurrent.TimeUnit.MINUTES);
        //?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
        return String.format("%s?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=%s#wechat_redirect",
                AUTH_URL,
                appId,
                URLEncoder.encode(redirectUri), // 需要URL编码
                state);
    }

    @Override
    public WeChatUserInfo handleCallback(String code, String state) {
        // 1. 验证state
        if (!validateState(state)) {
            throw new RuntimeException("Invalid state parameter");
        }
        // 2. 通过code获取access_token
        AccessTokenResult tokenResult = getAccessToken(code);

        // 3. 获取用户信息
        return getUserInfo(tokenResult.getAccessToken(), tokenResult.getOpenid());
    }

    /**
     * 获取用户基本信息
     */
    private WeChatUserInfo getUserInfo(String accessToken, String openid) {
        String url = String.format("%s?access_token=%s&openid=%s",
                USER_INFO_URL, accessToken, openid);

        Request request = new Request.Builder().url(url).get().build();

        try (Response response = httpClient.newCall(request).execute()) {
            String responseBody = response.body().string();

            cn.hutool.json.JSONObject json = cn.hutool.json.JSONUtil.parseObj(responseBody);

            if (json.containsKey("errcode")) {
                throw new RuntimeException("获取用户信息失败: " + json.getStr("errmsg"));
            }

            WeChatUserInfo userInfo = new WeChatUserInfo();
            userInfo.setOpenid(json.getStr("openid"));
            userInfo.setUnionid(json.getStr("unionid"));
            userInfo.setNickname(json.getStr("nickname"));
            userInfo.setSex(json.getInt("sex"));
            userInfo.setProvince(json.getStr("province"));
            userInfo.setCity(json.getStr("city"));
            userInfo.setCountry(json.getStr("country"));
            userInfo.setHeadimgurl(json.getStr("headimgurl"));
            userInfo.setPrivilege(json.getJSONArray("privilege").toList(String.class));
            return userInfo;

        } catch (IOException e) {
            log.error("获取用户信息异常", e);
            throw new RuntimeException("获取用户信息失败");
        }
    }

    /**
     * 通过code获取access_token
     */
    private AccessTokenResult getAccessToken(String code) {
        String url = String.format("%s?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
                ACCESS_TOKEN_URL, appId, appSecret, code);

        Request request = new Request.Builder().url(url).get().build();

        try (Response response = httpClient.newCall(request).execute()) {
            String responseBody = response.body().string();

            cn.hutool.json.JSONObject json = cn.hutool.json.JSONUtil.parseObj(responseBody);

            if (json.containsKey("errcode")) {
                throw new RuntimeException("获取access_token失败: " + json.getStr("errmsg"));
            }

            AccessTokenResult result = new AccessTokenResult();
            result.setAccessToken(json.getStr("access_token"));
            result.setExpiresIn(json.getInt("expires_in"));
            result.setRefreshToken(json.getStr("refresh_token"));
            result.setOpenid(json.getStr("openid"));
            result.setScope(json.getStr("scope"));
            result.setUnionid(json.getStr("unionid"));

            return result;

        } catch (IOException e) {
            log.error("获取access_token异常", e);
            throw new RuntimeException("微信登录服务暂时不可用");
        }
    }

    /**
     * 验证state有效性，初次不能删除，使用完整服务删除会导致验证失败
     */
    private boolean validateState(String state) {
        if (StringUtils.isEmpty(state)) {
            return false;
        }
        String key = "wechat:state:" + state;
        Boolean exists = redisCache.hasKey(key);

        if (Boolean.TRUE.equals(exists)) {
            // 不删除state，让用户可以在短时间内重复使用
            // 设置较短的过期时间（2分钟）来自动清理
            redisCache.expire(key, 2, java.util.concurrent.TimeUnit.MINUTES);
            return true;
        }
        return false;
    }

    /**
     * 验证state有效性
     */
//    private boolean validateState(String state) {
//        if (StringUtils.isEmpty(state)) {
//            return false;
//        }
//        String key = "wechat:state:" + state;
//        Boolean exists = redisCache.hasKey(key);
//        log.info("key: {}", key);
//        log.info("验证exists: {}", exists);
//        if (Boolean.TRUE.equals(exists)) {
//            // 验证成功后删除，防止重复使用
//            redisCache.deleteObject(key);
//            return true;
//        }
//        return false;
//    }

    /**
     * 生成随机state
     */
    @Override
    public String generateState() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }
}
